#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

typedef int OptCall(const char*, const char*);

typedef struct {
    const char opt;
    OptCall* handler;
} CallHandler;

static int A_Handler(const char* n, const char* v)
{
    extern char** environ;
    int i = 0;

    while (environ[i]) {
        printf("%s\n", environ[i++]);
    }
    
    return 0;
}

static int R_Handler(const char* n, const char* v)
{
    if (n) {
        printf("%s = %s\n", n, getenv(n));
    } else {
        printf("Need environ Name to read value...\n");
    }

    return 0;
}

static int W_Handler(const char* n, const char* v)
{
    int err = 1;

    if (n && v) {
        char* kv = malloc(strlen(n) + strlen(v) + 2);
        if (kv) {
            strcpy(kv, n);
            strcat(kv, "=");
            strcat(kv, v);

            err = putenv(kv);
            if (!err) {
                printf("Write New environ:%s\n\n\n", kv);
            } else {
                printf("Error on writing new environ value...\n");
            }
        }

        // free(kv); // <== 注意这里
    } else {
        printf("Need Name and Value to write environ...\n");
    }

    return err;
}

static int T_Handler(const char* n, const char* v)
{
    return W_Handler(n, v) || A_Handler(n, v);
}

static const CallHandler g_handler[] = {
    {'a', A_Handler},
    {'r', R_Handler},
    {'w', W_Handler},
    {'t', T_Handler},
};

static const int g_len = sizeof(g_handler) / sizeof(*g_handler);

int main(int argc, char* argv[])
{
    int c = 0;
    char opt = 0;
    char* name = NULL;
    char* value = NULL;

    while ((c = getopt(argc, argv, "arwtn:v:")) != -1) {
        switch(c) {
            case 'a':
            case 'r':
            case 'w':
            case 't':
                opt = c;
                break;
            case 'n':
                name = optarg;
                break;
            case 'v':
                value = optarg;
                break;
            default:
                exit(-1);
        }
    }

    c = 0;
    for (c = 0; c < g_len; c++) {
        if (opt == g_handler[c].opt) {
            g_handler[c].handler(name, value);
            break;
        }
    }

    return 0;
}

